/*
 * Bloque.cpp
 *
 *  Created on: 13/04/2014
 *      Author: ariel
 */

#include "Bloque.h"
#include "Const.h"
#include "Elemento.h"
#include "../../utils/utiles.h"

Bloque::Bloque()
{
	this->id = -1;
	this->capacity = Const::CAPACITY_Bloque;
	this->tam_dispersion = 0;
	this->initializeelements_asFreed();
}

Bloque::~Bloque() { }

Bloque::Bloque(int id, int tam_dispersion)
{
	this->id = id;
	this->capacity = Const::CAPACITY_Bloque;
	this->tam_dispersion = tam_dispersion;
	this->initializeelements_asFreed();

}

void Bloque::addElemento(Elemento* elemento)
{
	bool addOK = false;
	for (int i=0; i < this->capacity && !addOK; i++)
	{
		if ( this->elements[i]->isFreed() )
		{
			this->elements[i] = new Elemento(elemento->getRegistro(),i,Const::STATUS_BUSY);
			addOK = true;
		}
	}
}

void Bloque::deleteElemento(Elemento* Elemento)
{
	this->elements[Elemento->getId()]->setStatus(Const::STATUS_DELETED);
}

bool Bloque::isFreed()
{
	bool isFreed = true;
	for ( int i=0 ; i < this->capacity && isFreed; i++)
	{
		if ( this->elements[i]->isBusy() )
		{
			isFreed = false;
		}
	}

	return isFreed;
}

bool Bloque::existElemento(Twit* registro)
{
	bool exist = false;

	for ( int i=0 ; i < this->capacity && !exist; i++)
	{
		exist = this->elements[i]->getRegistro()->getId()==registro->getId();
	}

	return exist;
}


bool Bloque::isBusy()
{
	bool isBusy = true;
	for ( int i=0 ; i < this->capacity && isBusy; i++)
	{
			if ( this->elements[i]->isFreed() )
			{
				isBusy = false;
			}
	}

	return isBusy;
}

void Bloque::duplicate_tamDispersion()
{
	this->tam_dispersion = this->tam_dispersion*2;
}

void Bloque::reducirMitad_tamDispersion()
{
	this->tam_dispersion = this->tam_dispersion/2;
}


void Bloque::markelements_asFree()
{
	for (int i=0; i < this->capacity; i++)
	{
		this->elements[i]->setStatus(Const::STATUS_FREED);
	}
}

ostream& operator <<(ostream &o, const Bloque &b) {

	o<<"BloqueTwit "<<b.id<<": ";
	o<<"td("<<b.tam_dispersion<<");"<<endl;

	for (int i=0; i < b.capacity; i++)
	{
		o<<"\t"<<*b.elements[i]<<endl;
	}

	cout<<endl;

	return o;
}

void Bloque::markElemento_asBusy(Elemento* Elemento)
{
	this->elements[Elemento->getId()]->setStatus(Const::STATUS_BUSY);
}

Elemento* Bloque::getElemento(Twit* registro)
{
	bool encontrado = false;
	//Elemento* Elemento_actual = new Elemento();
	Elemento* Elemento_actual;
	for (int i=0; i < this->capacity && !encontrado; i++)
	{
		Elemento_actual = this->elements[i];
		encontrado = Elemento_actual->getRegistro()->getId()==registro->getId();
	}

	return Elemento_actual;
}

void Bloque::initializeelements_asFreed()
{
	for (int i=0; i < this->capacity; i++)
	{
		this->elements.push_back(new Elemento(new Twit(),i,Const::STATUS_FREED));
	}
}

int Bloque::getCapacity(){
	return this->capacity;
}

void Bloque::setCapacity(int capacity) {
	this->capacity = capacity;
}

vector<Elemento*> Bloque::getelements()
{
	return this->elements;
}

void Bloque::setelements(vector<Elemento*> elements) {

	this->elements.clear();

	for ( unsigned i=0 ; i < elements.size() ; i++)
	{
		this->elements.push_back(elements[i]);
	}
}

int Bloque::getId() {
	return this->id;
}

void Bloque::setId(int id) {
	this->id = id;
}

int Bloque::getTamDispersion() {
	return this->tam_dispersion;
}

void Bloque::setTamDispersion(int tamDispersion) {
	this->tam_dispersion = tamDispersion;
}

/*****************************************
 * Metodos de persistencia
 *****************************************/

string Bloque::serialize() {

	string buffer 	= "";
	string id  		= Util::SerializeInt(this->id);
	string capacity = Util::SerializeInt(this->capacity);
	string tam_disp = Util::SerializeInt(this->tam_dispersion);

	buffer.append(id.c_str(), sizeof(int));
	buffer.append(capacity.c_str(), sizeof(int));
	buffer.append(tam_disp.c_str(), sizeof(int));

	for (int i=0; i < this->capacity ; i++)
	{
		Elemento* elem = elements[i];
		string elemento = elem->serialize();
		buffer.append(elemento.c_str(), elem->getDataSize());
	}

	return buffer;
}

void Bloque::unserialize(std::string &buffer) {

	this->id = Util::DeSerializeInt(buffer);
	this->capacity = Util::DeSerializeInt(buffer);
	this->tam_dispersion = Util::DeSerializeInt(buffer);

	for (int i=0; i < this->capacity ; i++)
	{
		elements[i]->unserialize(buffer);
	}

}

int Bloque::getDataSize(){

	int dataSize = 0;
	for (int i=0; i < this->capacity ; i++)
	{
		dataSize += elements[i]->getDataSize();
	}

	return ( sizeof(int)+sizeof(int)+sizeof(int)+dataSize );
}
